package com.jrx.anytxn.param.job.bactchBillCompare.config;

import com.jrx.anytxn.common.uitl.DateUtils;
import com.jrx.anytxn.common.uitl.FileUtils;
import com.jrx.anytxn.common.uitl.InternetUtils;
import com.jrx.anytxn.common.uitl.JsonUtils;
import com.jrx.anytxn.common.uitl.SeqUtils;
import com.jrx.anytxn.common.uitl.StringUtils;
import com.jrx.anytxn.feign.gateway.bean.ApiResponse;
import com.jrx.anytxn.feign.gateway.request.CoreRequest19;
import com.jrx.anytxn.feign.gateway.response.CoreResponse19;
import com.jrx.anytxn.feign.gateway.service.IInnerGatewayService;
import com.jrx.anytxn.number.service.ISegmentService;
import com.jrx.anytxn.param.config.BillCompareConfig;
import com.jrx.anytxn.param.config.PathFileConfig;
import com.jrx.anytxn.param.constant.Constant;
import com.jrx.anytxn.param.entity.PrOrganizationTable;
import com.jrx.anytxn.param.entity.TlThirdBillDetail;
import com.jrx.anytxn.param.mapper.ext.ExtTlThirdBillDetailMapper;
import com.jrx.anytxn.param.service.system.IOrganizationTableService;
import org.apache.commons.collections.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
import org.springframework.batch.core.step.tasklet.Tasklet;
import org.springframework.batch.repeat.RepeatStatus;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
import org.springframework.util.StopWatch;

import javax.annotation.Resource;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.Objects;

/**
 * T24对账-账务文件检查是否存在job
 */
@Configuration
@EnableConfigurationProperties(PathFileConfig.class)
public class BatchT24BillFileCheckAndReadConfiguration {

    private static final Logger logger = LoggerFactory.getLogger(BatchT24BillFileCheckAndReadConfiguration.class);

    @Autowired
    public JobBuilderFactory jobBuilderFactory;

    @Autowired
    public StepBuilderFactory stepBuilderFactory;

    @Autowired
    private IOrganizationTableService organizationTableService;

    @Autowired
    private BillCompareConfig billCompareConfig;

    @Lazy
    @Autowired
    private IInnerGatewayService innerGatewayService;

    @Autowired
    private ISegmentService iSegmentService;

    @Resource
    private ExtTlThirdBillDetailMapper extTlBillThirdDetailMapper;

    @Bean
    public Job t24BillFileCheckAndReadJob() throws IOException {
        return jobBuilderFactory.get("t24BillFileCheckAndReadJob")
                .start(t24BillFileCheckAndReadStep())
                .build();
    }

    @Bean
    public Step t24BillFileCheckAndReadStep() throws IOException {
        return stepBuilderFactory.get("t24BillFileCheckAndReadStep").tasklet(t24BillFileCheckAndReadTasklet()).build();
    }

    @Bean
    public Tasklet t24BillFileCheckAndReadTasklet() {
        return (stepContribution, chunkContext) -> {
            PrOrganizationTable org = organizationTableService.findByOrgIdForBatch(Constant.XIB_ORG_NUMBER);
            // 设置指定对账日期
            Date today = billCompareConfig.getToday();
            if (Objects.nonNull(today)) {
                org.setToday(today);
            }
            String thirdChannel = billCompareConfig.getThirdChannel();
            // 清理指定日期的渠道对账数据
            extTlBillThirdDetailMapper.deleteByBusDate(org.getToday(), thirdChannel);
            String fileDate = DateUtils.format(org.getToday(), DateUtils.DATE_PATTERN_ANOTHER);
            String businessDate = DateUtils.format(org.getToday());
            //  /data/file/xaj
            String path = billCompareConfig.getFilePath() + File.separator + thirdChannel + File.separator + "transaction";
            logger.info("交易流水文件检查开始，渠道号:{} 业务日期为:{} 路径为:{} ", thirdChannel, businessDate, path);
            CoreRequest19 coreRequest19 = new CoreRequest19();
            coreRequest19.setTenantId(org.getTenantId());
            coreRequest19.setServiceId("txn");
            coreRequest19.setServiceIp(InternetUtils.getLocalIp());
            coreRequest19.setServiceSeq(SeqUtils.getSN());
            coreRequest19.setExtBusinessStartDate(fileDate);
            coreRequest19.setExtBusinessEndDate(fileDate);
            checkAndReadBillFile(path, businessDate, thirdChannel, 1, org, coreRequest19);

            return RepeatStatus.FINISHED;
        };
    }

    private void checkAndReadBillFile(String path, String businessDate, String thirdChannel, int count, PrOrganizationTable org, CoreRequest19 coreRequest19) throws Exception {
        if (count <= 3) {
            //调用生成对账文件接口
            ApiResponse<CoreResponse19> resp = innerGatewayService.entrustedPayment(JsonUtils.toJSon(coreRequest19));
            if (null == resp || "0000".equals(resp.getCode() + "") || null == resp.getData() || CollectionUtils.isEmpty(resp.getData().getFileNames())) {
                //当接口失败或者没有返回文件名，需重试
                checkAndReadBillFile(path, businessDate, thirdChannel, count + 1, org, coreRequest19);
            } else {
                List<String> fileNames = resp.getData().getFileNames();
                int i = 1;
                while (i <= billCompareConfig.getReadCount()) {
                    boolean flg = true;
                    List<File> files = FileUtils.findFiles(path);
                    for (String fileName : fileNames) {
                        long flgCount = files.stream().filter(file -> (fileName + ".flg").equals(file.getName())).count();
                        if (flgCount == 0) {
                            flg = false;
                            break;
                        }
                        long fileCount = files.stream().filter(file -> fileName.equals(file.getName())).count();
                        if (fileCount == 0) {
                            flg = false;
                            break;
                        }
                    }
                    if (flg) {
                        logger.info(" flg 文件验证通过 业务日期为:{} ", businessDate);
                        readBillFile(path, org, fileNames);
                        return;
                    }

                    Thread.sleep(billCompareConfig.getReadPeriod());
                    i++;
                }

                if (i > billCompareConfig.getReadCount()) {
                    logger.error("渠道{}文件循环检查已超过{}次，检查作业将停止。业务日期为:{}", thirdChannel, billCompareConfig.getReadCount(), businessDate);
                }
            }
        } else {
            logger.error("生成渠道{}文件接口失败已超过3次，检查作业将停止。业务日期为:{}", thirdChannel, businessDate);
        }
    }

    private void readBillFile(String path, PrOrganizationTable org, List<String> fileNames) throws Exception {
        List<TlThirdBillDetail> detailList = new LinkedList<>();
        StopWatch stopWatch = new StopWatch("文件读取耗时统计");
        for (String fileName : fileNames) {
            File file = new File(path + File.separator + fileName);
            logger.info("开始处理 : {}", file.getName());
            stopWatch.start(file.getName());
            InputStreamReader reader = new InputStreamReader(new FileInputStream(file), StandardCharsets.UTF_8); // 建立一个输入流对象reader
            BufferedReader br = new BufferedReader(reader); // 建立一个对象，它把文件内容转成计算机能读懂的语言\
            String line;
            while ((line = br.readLine()) != null) {
                logger.info("数据行 : {}", line);
                if (0 == line.length()) {
                    logger.warn("存在为空的一行数据");
                    continue;
                }
                TlThirdBillDetail detail = buildDetail(getBatchNumber(file.getName()), org, line, iSegmentService.getId(Constant.TL_THIRD_BILL_SUMMARY_TABLE));
                logger.info(detail.toString());
                detailList.add(detail);

                if (detailList.size() == 5000) {
                    detailList.forEach(d -> extTlBillThirdDetailMapper.insertSelective(d));
                    detailList.clear();
                }
            }
            if (CollectionUtils.isNotEmpty(detailList)) {
                detailList.forEach(d -> extTlBillThirdDetailMapper.insertSelective(d));
            }
            stopWatch.stop();
            logger.info("交易流水文件读取结束 文件名:{}  路径:{}", file.getName(), file.getPath());
        }
        if (CollectionUtils.isNotEmpty(fileNames)) {
            logger.info("交易流水文件读取完毕 业务日:{}  文件数量:{} 路径:{} \n {}", DateUtils.format(org.getToday()), fileNames.size(), path, stopWatch.prettyPrint());
        } else {
            logger.info("交易流水文件为空    业务日:{}              路径:{} \n {}", DateUtils.format(org.getToday()), path, stopWatch.prettyPrint());
        }
    }

    private String getBatchNumber(String fileName) {
        String[] split = fileName.trim().split("\\.", -1);
        String[] params = split[0].split("\\_", -1);
        String batchNumber = params[2];
        if (fileName.endsWith(".OUT")) {
            batchNumber = params[4];
        }
        return batchNumber;
    }

    private TlThirdBillDetail buildDetail(String batchNumber, PrOrganizationTable org, String line, long id) {

        TlThirdBillDetail detail = new TlThirdBillDetail();
        detail.setId(id);
        detail.setTenantId(org.getTenantId());
        detail.setOrganizationId(org.getOrganizationId());
        detail.setThirdChannel(billCompareConfig.getThirdChannel());
        detail.setBatchNumber(batchNumber);

        String[] params = line.trim().split("\\|", -1);

        if (StringUtils.isNotBlank(params[2])) {
            Date date = DateUtils.parseDate(params[2], DateUtils.DATE_PATTERN_ANOTHER);
            detail.setBusinessDate(date);
            detail.setThirdTime(date);
        }

        if (StringUtils.isNotBlank(params[5])) {
            detail.setThirdSeq(params[5]);
        }

        if (StringUtils.isNotBlank(params[0])) {
            detail.setOrgThirdSeq(params[0]);
        }

        if (StringUtils.isNotBlank(params[7])) {
            detail.setTransactionType(params[7]);
        }

        detail.setTransStatus("000000000");
        detail.setCompareFlag(Constant.COMPARE_FLAG_0);

        if (StringUtils.isNotBlank(params[6])) {
            detail.setCoreSeq(params[6]);
        }

        if (StringUtils.isNotBlank(params[3])) {
            detail.setCoreBusDate(params[3]);
        }

        detail.setDealDate(org.getToday());

        return detail;
    }
}
